﻿using System;
using System.Drawing;
using System.IO;
using System.IO.Ports;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using System.Windows.Forms;
using OpenCvSharp;
using OpenCvSharp.Extensions;

namespace Console
{
    public partial class Form1 : Form
    {
        // 是否为管理员
        private bool admin;

        // 创建一个 VideoCapture 对象，用于捕获摄像头的视频流（用于本地测试）
        private OpenCvSharp.VideoCapture capture;

        // 接收图像
        WebClient downloadImage;

        // 小车传输图像的URL
        private string _download_url = "http://192.168.124.3:5005/video";

        // 影像是否连接
        private bool video_connected = false;

        // 创建展示帧
        private OpenCvSharp.Mat frame;

        // 创建截图帧
        private OpenCvSharp.Mat shot;

        // OpenCV分辨率
        private OpenCvSharp.Size dp_resolution;

        // 长
        private Int32 _length = 960;

        // 宽
        private Int32 _width = 540;

        // 创建一个 Bitmap 对象，用于显示图像
        private Bitmap image;

        // 创建一个 Detector 对象，用于目标检测
        private Detector detector;

        // 是否开启目标检测
        private bool detecting = false;

        // 截图是否需要目标检测结果
        private bool detected = false;

        // 截图保存路径，默认为当前工作目录
        private string path = "";

        // 键盘捕获到的字母
        private volatile char keyPressed = '\0';

        // 当前X轴速度
        private byte vX = 0x00;

        // 上位机测试URL
        private string _test_url = "http://192.168.124.3:5005";

        // 发送HTTP数据报
        HttpClient postFrame;

        // HTTP数据报的URL
        //private string _post_url = "http://localhost:28086/data";
        private string _post_url = "http://192.168.124.3:28087/data/";

        // 是否能连接到上位机
        private bool upper_connected = false;

        public Form1(bool admin)
        {
            // 初始化Form1
            this.admin = admin;
            InitializeComponent();
        }

        private void picture_timer_Tick(object sender, EventArgs e)
        {

            byte[] imageBytes = downloadImage.DownloadData(_download_url);
            // Mat frame = new Mat();
            frame = Cv2.ImDecode(imageBytes, ImreadModes.Color);


            //// 从摄像头读取一帧图像
            //capture.Read(frame);

            // 检查图像是否为空
            if (frame.Empty())
            {
                return;
            }

            shot = frame.Clone();
            if (detecting == true)
            {
                frame = detector.detect(frame);
            }

            Cv2.Resize(frame, frame, dp_resolution);

            // 将 Mat 对象转换为 Bitmap 对象
            image = BitmapConverter.ToBitmap(frame);

            // 在 pictureBox 控件上显示图像
            pictureBox.Image = image;
        }

        private void pictureBox_Click(object sender, EventArgs e)
        {

        }

        private void button_test_Click(object sender, EventArgs e)
        {
            string url = _test_url; // Flask应用程序的URL

            try
            {
                using (WebClient client = new WebClient())
                {
                    string html = client.DownloadString(url);
                    MessageBox.Show("可以连接到上位机");
                    System.Console.WriteLine(html);
                    upper_connected = true;
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show("连接失败");
            }
        }

        private void button_video_Connect(object sender, EventArgs e)
        {
            // 尝试连接
            downloadImage = new WebClient();
            try
            {
                byte[] imageBytes = downloadImage.DownloadData(_download_url);
                video_connected = true;
                button_detect.Enabled = true;
                button_shot.Enabled = true;
            }
            catch (Exception ex)
            {
                System.Console.WriteLine(ex.Message);
                MessageBox.Show("连接失败，请检查接口配置");
                return;
            }

            // 按钮变换
            button_video.Text = "关闭影像";
            button_video.Click -= button_video_Connect;
            button_video.Click += button_video_Disconnect;

            // 设置帧的分辨率
            dp_resolution = new OpenCvSharp.Size(_length, _width);

            // 设置定时器，每隔 50 毫秒触发一次 Tick 事件
            timer.Interval = 50;
            timer.Tick += new EventHandler(picture_timer_Tick);
            timer.Start();
        }

        private void button_video_Disconnect(object sender, EventArgs e)
        {
            // 断开连接
            timer.Stop();
            downloadImage = null;
            frame = null;
            shot = null;
            video_connected = false;

            // 按钮变换
            button_video.Text = "开启影像";
            button_video.Click -= button_video_Disconnect;
            button_video.Click += button_video_Connect;
            button_detect.Enabled = false;
            button_shot.Enabled = false;

            // 图片重置
            pictureBox.Image = null;
        }

        private void button_detect_Start(object sender, EventArgs e)
        {
            detector = new Detector();
            detector.setup();
            detecting = true;
            button_detect.Text = "停止检测";
            button_video.Enabled = false;
            button_detect.Click -= button_detect_Start;
            button_detect.Click += button_detect_Stop;
        }

        private void button_detect_Stop(object sender, EventArgs e)
        {
            detector = null;
            detecting = false;
            button_detect.Text = "开始检测";
            button_video.Enabled = true;
            button_detect.Click -= button_detect_Stop;
            button_detect.Click += button_detect_Start;
        }

        private void button_interface_Click(object sender, EventArgs e)
        {
            Form2 form2 = new Form2(_download_url, _post_url, _test_url, this.Text, this.admin);
            form2.ShowDialog();
            _download_url = form2._download_url;
            _post_url = form2._post_url;
            _test_url = form2._test_url;
        }

        private void button_user_Click(object sender, EventArgs e)
        {
            Form4 form4 = new Form4();
            form4.ShowDialog();
        }

        private void textBox1_TextChanged(object sender, EventArgs e)
        {
            this.path = textBox1.Text;
        }

        private void button_path_Click(object sender, EventArgs e)
        {
            // 创建一个 FolderBrowserDialog 对象
            FolderBrowserDialog dialog = new FolderBrowserDialog();

            // 显示文件夹选择对话框
            if (dialog.ShowDialog() == DialogResult.OK)
            {
                // 更新 myPath 的值
                path = dialog.SelectedPath;
                textBox1.Text = path;
            }
        }

        private void button_shot_Click(object sender, EventArgs e)
        {
            if (shot != null)
            {
                string filepath = path + Path.DirectorySeparatorChar + DateTimeOffset.Now.ToUnixTimeSeconds().ToString() + ".jpg";
                Cv2.ImWrite(filepath, shot);
            }
        }

        private void Form1_KeyDown(object sender, KeyEventArgs e)
        {
            System.Console.WriteLine(_post_url);
            // 判断按下的键是否为 WASD 键
            switch (e.KeyCode)
            {
                case Keys.W:
                    keyPressed = 'W';
                    break;
                case Keys.A:
                    keyPressed = 'A';
                    break;
                case Keys.S:
                    keyPressed = 'S';
                    break;
                case Keys.D:
                    keyPressed = 'D';
                    break;
                case Keys.R:
                    keyPressed = 'R';
                    break;
                case Keys.F:
                    keyPressed = 'F';
                    break;
            }
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            int button_left = pictureBox.Right + (ClientSize.Width - pictureBox.Right - button_test.Width) / 2;
            button_test.Left = button_left;
            button_video.Left = button_left;
            button_detect.Left = button_left;
            button_interface.Left = button_left;
            button_user.Left = button_left;

            textBox1.Left = pictureBox.Right + (ClientSize.Width - pictureBox.Right - textBox1.Width) / 2;
            button_path.Top = textBox1.Bottom + button_video.Top - button_test.Top - button_test.Height;
            button_path.Left = textBox1.Left;
            button_shot.Top = button_path.Top;
            button_shot.Left = textBox1.Right - button_shot.Width;

            if (!this.admin)
            {
                this.button_user.Enabled = false;
                this.button_test.Enabled = false;
                this.label1.Text = "游客模式";
                this.label2.Text = "";
            }

            if (admin)
            {
                this.KeyPreview = true;
                this.KeyDown += Form1_KeyDown;
            }

            Timer time = new Timer();
            time.Interval = 1000; // 每隔1秒触发一次
            time.Tick += getTime;
            time.Start();

            path = Environment.CurrentDirectory;
            textBox1.Text = path;

            // 创建一个新的 Task 对象，用于执行遥控小车的操作
            Task controlCarTask = Task.Run(() =>
            {
                postFrame = new HttpClient();
                while (true) // 在这里编写遥控小车的代码
                {
                    // 处理按键输入，使用 Control.Invoke 方法来更新 GUI 界面
                    switch (keyPressed)
                    {
                        case 'W':
                            // 在这里编写处理 W 键的代码
                            System.Console.WriteLine("WWWWW");

                            // 发送前进的字节数组
                            byte[] frameW = GenerateBytes(1, vX, 0, 0);
                            var byteArrayContentW = new ByteArrayContent(frameW);
                            var responseW = postFrame.PostAsync(_post_url, byteArrayContentW);

                            // 委托：更新GUI界面
                            Invoke(new MethodInvoker(() =>
                            {
                                label1.Text = "运动轨迹：" + "W";
                            }));

                            // 恢复初始发送状态
                            keyPressed = '\0';
                            break;
                        case 'A':
                            // 在这里编写处理 A 键的代码
                            System.Console.WriteLine("AAAAA");

                            // 发送行进中左转向的字节数组
                            byte[] frameA = GenerateBytes(0, 0, 1, 20);
                            var byteArrayContentA = new ByteArrayContent(frameA);
                            var responseA = postFrame.PostAsync(_post_url, byteArrayContentA);

                            // 委托：更新GUI界面
                            Invoke(new MethodInvoker(() =>
                            {
                                label1.Text = "运动轨迹：" + "A";
                            }));

                            // 恢复初始发送状态
                            keyPressed = '\0';
                            break;
                        case 'S':
                            // 在这里编写处理 S 键的代码
                            System.Console.WriteLine("SSSSS");

                            // 发送后退的字节数组
                            byte[] frameS = GenerateBytes(0, vX, 0, 0);
                            var byteArrayContentS = new ByteArrayContent(frameS);
                            var responseS = postFrame.PostAsync(_post_url, byteArrayContentS);

                            // 委托：更新GUI界面
                            Invoke(new MethodInvoker(() =>
                            {
                                label1.Text = "运动轨迹：" + "S";
                            }));

                            // 恢复初始发送状态
                            keyPressed = '\0';
                            break;
                        case 'D':
                            // 在这里编写处理 D 键的代码
                            System.Console.WriteLine("DDDDD");

                            // 发送行进中左转向的字节数组
                            byte[] frameD = GenerateBytes(0, 0, 0, 20);
                            var byteArrayContentD = new ByteArrayContent(frameD);
                            var responseD = postFrame.PostAsync(_post_url, byteArrayContentD);

                            // 委托：更新GUI界面
                            Invoke(new MethodInvoker(() =>
                            {
                                label1.Text = "运动轨迹：" + "D";
                            }));

                            // 恢复初始发送状态
                            keyPressed = '\0';
                            break;
                        case 'R':
                            // 在这里编写处理 R 键的代码
                            System.Console.WriteLine("RRRRR");

                            // 增加档位
                            if (vX <= 0x50)
                                vX = (byte)(vX + 0x14);
                            Invoke(new MethodInvoker(() =>
                            {
                                // 在这里编写更新 GUI 界面的代码
                                label2.Text = "运动速度：" + vX.ToString();
                            }));
                            keyPressed = '\0';
                            break;
                        case 'F':
                            // 在这里编写处理 F 键的代码
                            System.Console.WriteLine("FFFFF");

                            // 减少档位
                            if (vX >= 0x14)
                                vX = (byte)(vX - 0x14);
                            Invoke(new MethodInvoker(() =>
                            {
                                // 在这里编写更新 GUI 界面的代码
                                label2.Text = "运动速度：" + vX.ToString();
                            }));
                            keyPressed = '\0';
                            break;
                    }
                }
            });
        }

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            // 停止定时器
            timer.Stop();
            // 释放资源
            //capture.Dispose();
            image.Dispose();
        }

        private void Form1_Layout()
        {

        }

        private byte[] GenerateBytes(int xD, int xV, int zD, int zV)
        {
            byte[] bytes = new byte[12];
            bytes[0] = 0x21;
            bytes[1] = 0x21;
            bytes[2] = 0x0A;
            bytes[3] = 0x00;
            bytes[4] = (byte)((xD > 0) ? 0x01 : 0x00);
            bytes[5] = (byte)xV;
            bytes[6] = 0x00;
            bytes[7] = 0x00;
            bytes[8] = (byte)((zD > 0) ? 0x01 : 0x00);
            bytes[9] = (byte)zV;
            short sum = 0;
            for (int i = 0; i < 10; i++)
            {
                sum = (short)(sum + (short)(bytes[i]));
            }

            bytes[10] = (byte)(sum & 0xFF);
            bytes[11] = (byte)(sum >> 8);
            return bytes;
        }

        private void getTime(object sender, EventArgs e)
        {
            label3.Text = "当前时间：" + DateTime.Now.ToString("HH:mm:ss");
        }

        private void capture_test()
        {
            // 初始化 VideoCapture 对象，参数为 0 表示使用默认的摄像头设备
            capture = new VideoCapture(0);

            // 检查摄像头是否打开成功
            if (!capture.IsOpened())
            {
                MessageBox.Show("无法打开摄像头");
                return;
            }

            // 配置图像参数
            capture.Set(VideoCaptureProperties.FourCC, VideoWriter.FourCC('M', 'J', 'P', 'G'));
            capture.Set(VideoCaptureProperties.FrameWidth, 960.0);
            capture.Set(VideoCaptureProperties.FrameHeight, 540.0);

            // 实例化Detector
            detector = new Detector();
            detector.setup();
        }
    }
}
